package com.zm.blog.aop;

import com.zm.blog.constants.CommonConst;
import com.zm.blog.entity.User;
import com.zm.blog.handle.BlogRuntimeException;
import com.zm.blog.utils.BlogUtil;
import com.zm.blog.utils.cache.BlogCache;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: Sister Xiao Ming
 * @Description:
 */
@Aspect
@Slf4j
@Component
@Order(1)    // 优先级稍低于登录检查
public class SaveCheckAspect {

    /**
     * 保存操作检查切面
     * @param joinPoint 连接点
     * @param saveCheck 保存检查注解
     * @return 方法执行结果
     * @throws Throwable
     */
    @Around("@annotation(saveCheck)")
    public Object checkSaveLimit(ProceedingJoinPoint joinPoint, SaveCheck saveCheck) throws Throwable {

        //1.管理员用户直接放行
        if (isAdminUser()) {
            return joinPoint.proceed();
        }

        //2.检查用户级保存限制
        boolean userLimitExceeded = checkUserSaveLimit();

        //3.检查 IP 级保存限制
        boolean ipLimitExceeded = checkIpSaveLimit();

        //4.任一限制超限则阻止操作
        if (userLimitExceeded || ipLimitExceeded) {
            throw new BlogRuntimeException("今日提交次数已用尽，请一天后再来！");
        }

        //5.执行目标方法
        return joinPoint.proceed();
    }

    /**
     * 判断当前用户是否为管理员
     * @return
     */
    private boolean isAdminUser() {
        String token = BlogUtil.getToken();
        if (!StringUtils.hasText(token)) {
            return false;
        }

        User user = (User) BlogCache.get(token);
        if (user == null) {
            return false;
        }

        User adminUser = BlogUtil.getAdminUser();
        return user.getId().equals(adminUser.getId());
    }

    /**
     * 检查用户级保存限制
     * @return 是否超过限制
     */
    private boolean checkUserSaveLimit() {
        String token = BlogUtil.getToken();
        if (!StringUtils.hasText(token)) {
            return false;
        }

        User user = (User) BlogCache.get(token);
        if (user == null) {
            return false;
        }

        //获取或创建用户计数器
        String userKey = CommonConst.SAVE_COUNT_USER_ID + user.getId();
        AtomicInteger userCounter = getOrCreateCounter(userKey);

        //检查并递增计数
        int userCount = userCounter.getAndIncrement();
        if (userCount >= CommonConst.SAVE_MAX_COUNT) {
            log.warn("用户保存超限：{}，次数：{}", user.getId(), userCount);
            return true;
        }
        return false;
    }

    /**
     * 获取或创建计数器
     * @param cacheKey 缓存键
     * @return 计数器对象
     */
    private AtomicInteger getOrCreateCounter(String cacheKey) {
        AtomicInteger counter = (AtomicInteger) BlogCache.get(cacheKey);
        if (counter == null) {
            counter = new AtomicInteger(0);
            BlogCache.put(cacheKey, counter, CommonConst.SAVE_EXPIRE);
        }
        return counter;
    }

    /**
     * 检查 IP 级保存限制
     * @return 是否超过限制
     */
    private boolean checkIpSaveLimit() {
        String ip = BlogUtil.getIpAddr(BlogUtil.getRequest());
        if (!StringUtils.hasText(ip)) {
            return false;
        }

        //获取或创建 IP 计数器
        String ipKey = CommonConst.SAVE_COUNT_IP + ip;
        AtomicInteger ipCounter = getOrCreateCounter(ipKey);

        //检查并递增计数
        int ipCount = ipCounter.getAndIncrement();
        if (ipCount > CommonConst.SAVE_MAX_COUNT) {
            log.warn("IP保存超限：{}，次数：{}", ip, ipCount);
            return true;
        }
        return false;
    }
}
